import { Show } from "@/component/Display";
import { SearchOutlined } from "@ant-design/icons";
import { Empty, Input, InputRef, Menu, MenuProps, MenuRef } from "antd";
import { ItemType, MenuItemGroupType, MenuItemType, SubMenuType } from "antd/es/menu/interface";
import { isString } from "lodash";
import { pinyin } from 'pinyin-pro';
import React, { useEffect, useMemo, useRef, useState } from "react";
import type { NavMenu } from "../hooks/useNavMenu";
import styles from "../styles.module.scss";
import { NavItemLabel } from "./NavItemLabel";
export interface IMainNavMenuProps {
  navMenu: NavMenu.IUseResult;
  navItems: MenuProps['items'];
}

function get_label_str(n: React.ReactNode): string {
  if (isString(n)) return n;
  if (React.isValidElement(n)) {
    if (NavItemLabel.is(n))
      return n.props.label
  }
  return '' + n;
}
export default function MainNavMenu(props: IMainNavMenuProps) {
  const { navMenu, navItems } = props
  const [search_value, set_search_value] = useState('');
  const { collapsed } = navMenu;
  const trimmed_search_value = search_value.trim().replace(/\//, '');
  const _navItems = useMemo(() => {
    if (!trimmed_search_value || !navItems || collapsed) return navItems
    const flat_nav_item = (item: ItemType, parents: (SubMenuType | MenuItemGroupType)[], outputs: MenuItemType[]) => {
      if (!item) return;
      if (item.type === 'item') {
        const name = parents
          .map(v => get_label_str(v.label))
          .concat(get_label_str(item.label))
          .join('/')

        if (name.indexOf(search_value) >= 0) {
          const regexp = new RegExp(search_value, 'g');
          let match;
          const label_children: React.ReactNode[] = [];
          let prev_index = 0;
          while ((match = regexp.exec(name)) !== null) {
            const normal_str = name.substring(prev_index, match.index)
            if (normal_str) label_children.push(normal_str)
            const highlight_str = name.substring(match.index, regexp.lastIndex)
            label_children.push(<b style={{ background: 'yellow' }}>{highlight_str}</b>)
            prev_index = regexp.lastIndex
          }
          const normal_str = name.substring(prev_index, name.length)
          if (normal_str) label_children.push(normal_str)
          outputs.push({
            key: item.key,
            label: <>{label_children}</>,
            icon: item.icon || (parents.find(v => (v as any).icon) as any)?.icon,
          })
          return;
        }
        const full_pinyin = pinyin(name, { toneType: 'none' }).replace(/\s/g, '')
        const head_pinyin = pinyin(name, { pattern: 'first' }).replace(/\s/g, '')
        if (full_pinyin.indexOf(search_value.toLowerCase()) >= 0 || head_pinyin.indexOf(search_value.toLowerCase()) >= 0) {
          outputs.push({
            key: item.key,
            label: <>{name}</>,
            icon: item.icon || (parents.find(v => (v as any).icon) as any)?.icon,
          })
        } else {
          return
        }
      } else if (item.type === 'group' || item.type === 'submenu') {
        if (item.children) {
          for (const i of item.children) {
            flat_nav_item(i, parents.concat(item), ret)
          }
        }
      }

    }
    const ret: MenuItemType[] = []
    for (const i of navItems)
      flat_nav_item(i, [], ret)
    return ret;
  }, [navItems, trimmed_search_value, collapsed])

  const ref_input = useRef<InputRef>(null);
  const ref_menu = useRef<MenuRef>(null);

  useEffect(() => {
    const ele = ref_input.current?.input;
    if (!ele) return
    const on_key_down = (e: KeyboardEvent) => {
      const first_nav_menu_item = get_first_item_ele();
      const last_nav_menu_item = get_last_item_ele();
      switch (e.key?.toUpperCase()) {
        case 'ARROWUP':
          e.preventDefault();
          e.stopPropagation();
          e.stopImmediatePropagation();
          ref_input.current?.input?.blur()
          last_nav_menu_item?.focus()
          break;
        case 'ARROWDOWN':
          e.preventDefault();
          e.stopPropagation();
          e.stopImmediatePropagation();
          ref_input.current?.input?.blur()
          first_nav_menu_item?.focus()
          break;
        case 'ESCAPE':
          e.preventDefault();
          e.stopPropagation();
          e.stopImmediatePropagation();
          if (ref_input.current?.input) {
            /*
            NOTE: 
              此处set_search_value无效，因为search_value将在onBlur中被覆盖。故直接设置元素值。
              -Gim 
            */
            ref_input.current.input.value = '';
            ref_input.current.input.blur()
          }
          break;
        default:
          return;
      }
    }
    ele.addEventListener('keydown', on_key_down);
    return () => ele.removeEventListener('keydown', on_key_down)
  }, [])

  useEffect(() => {
    const ele = ref_menu.current?.menu?.list;
    if (!ele) return;

    const on_key_down = (e: KeyboardEvent) => {
      switch (e.key?.toUpperCase()) {
        case 'ARROWUP':
          if (get_first_item_ele() === document.activeElement) {
            ref_input.current?.focus();
            e.preventDefault();
            e.stopPropagation();
            e.stopImmediatePropagation();
          }
          break;
        case 'ARROWDOWN':
          if (get_last_item_ele() === document.activeElement) {
            ref_input.current?.focus();
            e.preventDefault();
            e.stopPropagation();
            e.stopImmediatePropagation();
          }
          break;
        case 'ESCAPE':
          /*
          NOTE: 
            直接<Menu onKeyDown/> 无法响应ESCAPE 
            -Gim
          */
          e.preventDefault();
          set_search_value('');
          break;
      }
    }
    ele.addEventListener('keydown', on_key_down);
    return () => ele.removeEventListener('keydown', on_key_down)
  }, [])

  return (
    <>
      {/* 太少时不需要
      <Show.Div yes={!collapsed} withAnim style={{ padding: '10px 10px 0px' }} tabIndex={-1}>
        <Input
          placeholder="快速搜索"
          allowClear
          ref={ref_input}
          prefix={<SearchOutlined />}
          value={search_value}
          onChange={e => set_search_value(e.target.value)}
          onBlur={e => set_search_value(e.target.value.trim())} />
      </Show.Div> 
      */}
      <Show.Div yes={!collapsed && !_navItems?.length} style={{ padding: 10 }}>
        <Empty />
      </Show.Div>
      <Menu
        ref={ref_menu}
        className={styles.nav_menu}
        mode="inline"
        items={_navItems}
        onClick={v => navMenu.select(v.key)}
        selectedKeys={[navMenu.selectedKey]}
        openKeys={navMenu.openKeys || []}
        onOpenChange={navMenu.setOpenKeys}
        triggerSubMenuAction='hover' />
    </>
  )
}
const get_first_item_ele = () => {
  const ret = document.querySelector(`.${styles.nav_menu}>.ant-menu-item:first-child`)
    || document.querySelector(`.${styles.nav_menu}>.ant-menu-submenu:first-child>.ant-menu-submenu-title`);
  return ret as HTMLElement | null | undefined
}
const get_last_item_ele = () => {
  const ret = document?.querySelector(`.${styles.nav_menu}>.ant-menu-item:last-child`)
    || document.querySelector(`.${styles.nav_menu}>.ant-menu-submenu:last-child>.ant-menu-submenu-title`);
  return ret as HTMLElement | null | undefined
}